/**
 * \file
 */

#ifndef NETWORK_H
#define NETWORK_H

#include "node.h"
#include "constants.h"

/*! @file network.h
 *  @brief < Estructura y funciones del network >
 */
 
typedef struct s_network *network;

/*! @fn network_create()
 *  @brief Crea un network.
 *  @return Un nuevo network.
 */
network network_create(void);

/*! @fn network_add(network n, unsigned int from, unsigned int to, 
                    unsigned  int cap, unsigned int flow)
 *  @brief Creador del network.
 *  @pre <code> (n != NULL) </code>
 *  @param n El network al que le vamos a agregar los nodos y aristas.
 *  @param from El nombre del nodo origen.
 *  @param to El nomre del nodo destino.
 *  @param cap La capacidad de a arista.
 *  @param flow El flujo de la arista.
 */
void network_add(network n, unsigned int from, unsigned int to, 
                    unsigned  int cap, unsigned int flow);

/*! @fn network_find(network n, unsigned int name)
 *  @brief Busca y devuelve un nodo del network.
 *  @pre <code> (n != NULL) </code>
 *  @param n El network en el que vamos a buscar el nodo
 *  @param name El nombre del nodo a buscar.
 *  @return El nodo o NULL si no esta.
 */
node network_find(network n, unsigned int name);

/*! @fn network_destroy(network n)
 *  @brief Destructor del network.
 *  @pre <code> (n != NULL) </code>
 *  @param n El network que queremos destruir.
 */
void network_destroy(network n);

/*! @fn network_helper_create(network n)
 *  @brief Crea un network auxiliar.
 *  @pre <code> (n != NULL) </code>
 *  @param n El network que queremos destruir.
 *  @return El network auxiliar.
 */
network network_helper_create(network n);

/*! @fn network_helper_add(network n, unsigned int from, unsigned int to, 
                    unsigned  int cap, unsigned int flow, bool flow)
 *  @brief Creador del network.
 *  @pre <code> (n != NULL) </code>
 *  @param n El network auxiliar al que le vamos a agregar los nodos y aristas.
 *  @param from El nombre del nodo origen.
 *  @param to El nomre del nodo destino.
 *  @param cap La capacidad de a arista.
 *  @param flow El flujo de la arista.
 *  @param backward Para indicar si agregamos la arista en backward.
 */
void network_helper_add(network n, unsigned int from, unsigned int to, 
                        unsigned  int cap, unsigned int flow, 
                            bool backward);

/*! @fn network_path_exists(network nh)
 *  @brief Indica si hay un camino en el network hasta t.
 *  @pre <code> (nh != NULL) </code>
 *  @param n El network en el que queremos saber si hay camino.
 *  @return Verdadero si hay un camino hacia t.
 */
bool network_path_exists(network n);

/*! @fn network_cut_calculate(network n)
 *  @brief Imprime el corte en un network auxiliar en el archivo
 *         "cut.txt"
 *  @pre <code> (n != NULL) </code>
 *  @param nh El network auxiliar del cual queremos calcular el corte
 */
void network_cut_calculate(network n);

/*! @fn network_flow_calculate(network nh)
 *  @brief Imprime el flujo total en el archivo "flow.txt".
 *  @pre <code> (n != NULL) </code>
 *  @param n El network del cual queremos imprimir el flujo.
 */
void network_flow_calculate(network n);

/*! @fn network_increase_flow(plist_t path, network n, 
                            unsigned int min_flow)
 * @brief Incrementa el flujo de las aristas que estan en path en
 *        una cantidad min_flow para el network n
 *  @pre <code> (n != NULL) </code>
 *  @pre <code> (path != NULL) </code>
 * @param path     El camino de aristas de s a t en las que hay que 
 *                 aumentar el flujo
 * @param min_flow La cantidad de flujo que puede enviar el camino
 * @param n         El network en el que queremos aumentar el flujo
 */
void network_increase_flow(plist_t path, network n, 
                            unsigned int min_flow);

/**
 * @brief Calcula el flujo máximo, es decir la sumatoria de los flujos
 * que salen de s
 *  @pre <code> (n != NULL) </code>
 * @param n El network en el que queremos calcular el flujo máximo
 * @return El flujo máximo del network. 
 */
unsigned int network_max_flow_calculate(network n);

/*! @fn network_helper_increase_flow(plist_t path, network n)
 * @brief Incrementa el flujo de las aristas que estan en path.
 *  @pre <code> (n != NULL) </code>
 *  @pre <code> (path != NULL) </code>
 * @param path     El camino de aristas de s a t en las que hay que 
 *                 aumentar el flujo
 * @param n         El network en el que queremos aumentar el flujo
 * @return La cantidad de flujo que el camino aumento. 
 */
unsigned int network_helper_increase_flow(plist_t path, network n);


#endif
